﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace LightCAD.Drawing.Actions
{
    public class AxisGridAction : ElementAction
    {
        public AxisGridAction(IDocumentEditor docEditor)
      : base(docEditor)
        {
            LcDocument = docEditor.DocRt.Document;
        }
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;
        public AxisGridAction()
        {

            CreateMethods = new LcCreateMethod[2];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "AxisGrid",
                Description = "创建轴网",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "" },
                }
            };
            CreateMethods[1] = new LcCreateMethod()
            {
                Name = "AxisNum",
                Description = "轴网编号",
                Steps = new LcCreateStep[]
        {
                    new LcCreateStep { Name=  "Step1", Options= "" },
        }
            };
        }
        internal static void Initilize()
        {
            ElementActions.AxisGrid = new AxisGridAction();
            LcDocument.ElementActions.Add(BuiltinElementType.AxisGrid, ElementActions.AxisGrid);
        }
        private PointInputer inputer { get; set; }
        public LcDocument LcDocument;
        private ElementInputer ElementInputer { get; set; }
        private CmdTextInputer CmdTextInputer { get; set; }
        private LcCreateMethod GetMethod(string method)
        {
            if (method == null) return CreateMethods[0];
            var getted = CreateMethods.FirstOrDefault((m) => m.Name == method);
            if (getted == null)
                return CreateMethods[0];
            else
                return getted;
        }
        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            this.inputer = new PointInputer(this.docEditor);
            this.CmdTextInputer = new CmdTextInputer(this.docEditor);
            var elementSetInputer = new ElementSetInputer(this.docEditor);
            var elementInputer = new ElementInputer(this.docEditor);
            var method = "CreateARC";
            if (args != null && args.Length > 0)
            {
                method = args[0];
            }
            var curMethod = this.GetMethod(method);
            if (curMethod.Name == "AxisGrid")
            {

                LcAxisGrid lcAxisGrid;
                var win = (IAxisLineManageFrom)AppRuntime.UISystem.CreateWindow("AxisManageFrom", this);
                var result = AppRuntime.UISystem.ShowDialog(win);
                if (result == LcDialogResult.OK)
                {
                    if (win.CurrentAction == "InsertAxisGrid")
                    {
                        var resultPoint = await this.inputer.Execute("选择第一个点：");
                        if (resultPoint == null)
                        {
                            goto End;
                        }
                        if (resultPoint.ValueX != null)
                        {
                            var basePoint = (Vector2)resultPoint.ValueX;
                            lcAxisGrid = win.lcAxisGrid;
                            lcAxisGrid.BasePoint = basePoint.Clone();
                            LcDocument.ModelSpace.InsertElement(lcAxisGrid);
                        }
                        goto End;
                    }
                }
                else { goto End; }
            }
            else if (curMethod.Name == "AxisNum")
            {
            Step1:
                var win = (IAxisLineManageFrom)AppRuntime.UISystem.CreateWindow("AxisNumberSettingFrom", this);
                var result = AppRuntime.UISystem.ShowDialog(win);
                if (result == LcDialogResult.OK)
                {
                    if (win.CurrentAction == "InsertAxisNum")
                    {
                        var elements = this.docRt.Document.ModelSpace.Elements.Where(x => x.Type == BuiltinElementType.AxisLine).ToList();
                        List<LcAxisLine> lcAxisLines = (from element in elements
                                                        where element is LcAxisLine
                                                        select element as LcAxisLine).ToList();
                    Step1_1:
                        var result1 = await elementInputer.Execute("选择开始轴网：");

                        if (result1 == null)
                        {
                            goto End;
                        }

                        if (result1.ValueX != null)
                        {
                            var firstElement = ((LcElement)result1.ValueX);
                            if (!(firstElement is LcAxisLine))
                            {
                                goto Step1_1;
                            }
                            var firstLcAxisLine = firstElement as LcAxisLine;
                        Step1_2:
                            var result2 = await elementInputer.Execute("选择结尾轴网：");
                            if (result2 == null)
                            {
                                goto End;
                            }
                            var endElement = ((LcElement)result2.ValueX);
                            if (!(endElement is LcAxisLine))
                            {
                                goto Step1_2;
                            }
                            var Normalize = (endElement as LcAxisLine).Vector.Normalize();
                            var Normalize2 = firstLcAxisLine.Vector.Normalize();

                            if (endElement == null || !(endElement is LcAxisLine) || new Vector2(Math.Round(Normalize.X), Math.Round(Normalize.Y)) != new Vector2(Math.Round(Normalize2.X), Math.Round(Normalize2.Y)))
                            {
                                goto Step1_2;
                            }
                            var firstIndex = lcAxisLines.IndexOf(firstLcAxisLine);
                            var endIndex = lcAxisLines.IndexOf(endElement as LcAxisLine);

                            var selectEles = this.docRt.Action.SelectedElements;
                            selectEles.Clear();
                            if (firstIndex < endIndex)
                            {
                                for (int i = firstIndex; i <= endIndex; i++)
                                {
                                    selectEles.Add(lcAxisLines[i]);
                                }
                            }
                            else
                            {
                                for (int i = firstIndex; i >= endIndex; i--)
                                {
                                    selectEles.Add(lcAxisLines[i]);
                                }
                            }
                            var selectPoint1 = (Vector2)result1.Extent;
                            var selectPoint2 = (Vector2)result2.Extent;
                            var radius = win.Radius;
                            if (radius == 0)
                            {
                                radius = 200;
                            }

                            int axisNumInt = 0;
                            var orderingRule = win.OrderingRule;
                            var firstAxisNum = win.FirstAxisNum;
                            foreach (LcAxisLine lcAxisLine in selectEles)
                            {
                                lcAxisLine.StartLeadLines.Clear();
                                lcAxisLine.StartCircleHandle.Clear();
                                lcAxisLine.EndLeadLines.Clear();
                                lcAxisLine.EndCircleHandle.Clear();
                                var line = lcAxisLine.AxisLine;


                                string axisNumText;
                                if (!string.IsNullOrEmpty(firstAxisNum))
                                {
                                    if (orderingRule == "1A=>2A=>3A")
                                    {
                                        axisNumText = $"{axisNumInt}{firstAxisNum.LastOrDefault()}";
                                    }
                                    else if (orderingRule == "1A=>1B=>1C")
                                    {
                                        axisNumText = $"1{Convert.ToChar('A' + axisNumInt).ToString()}";
                                    }
                                    else
                                    {
                                        axisNumText = axisNumInt.ToString();
                                    }
                                }
                                else
                                {
                                    double angle = Math.Atan2(line.End.Y - line.Start.Y, line.End.X - line.Start.X);
                                    double theta = line.Angle * 180 / Math.PI;
                                    theta = theta % 180;
                                    if (theta < 30)
                                    {
                                        axisNumText = Convert.ToChar('A' + axisNumInt).ToString();
                                    }
                                    else
                                    {
                                        axisNumText = (axisNumInt + 1).ToString();
                                    }
                                }


                                if (win.AxisNumType == "双侧标注")
                                {
                                    Vector2 vec = line.Start - line.End;
                                    double scale;
                                    scale = 1000 / vec.Length();
                                    Vector2 ladelEndPoint = line.Start + scale * vec;
                                    scale = radius / vec.Length();
                                    Vector2 textPoint = ladelEndPoint + scale * vec;
                                    lcAxisLine.StartLeadLines = new List<LcLine>() { CreateLcLine(line.Start, ladelEndPoint) };
                                    lcAxisLine.StartCircleHandle = new List<LcAxisCircle>() { CreateLcAxisCirle(textPoint, radius, axisNumText) };
                                    vec = line.End - line.Start;
                                    Vector2 vec2 = line.End - line.Start;
                                    var scale2 = 1000 / vec2.Length();
                                    var ladelEndPoint2 = line.End + scale2 * vec2;
                                    scale2 = radius / vec2.Length();
                                    var textPoint2 = ladelEndPoint2 + scale2 * vec2;
                                    lcAxisLine.EndLeadLines = new List<LcLine>() { CreateLcLine(line.End, ladelEndPoint2) };
                                    lcAxisLine.EndCircleHandle = new List<LcAxisCircle>() { CreateLcAxisCirle(textPoint2, radius, axisNumText) };
                                }
                                else if (win.AxisNumType == "单侧标注")
                                {
                                    if (GeoUtils.PointDistanceToLine(line.Start, selectPoint1, selectPoint2) < GeoUtils.PointDistanceToLine(line.End, selectPoint1, selectPoint2))
                                    {
                                        var vec = line.Start - line.End;
                                        var scale = 1000 / vec.Length();
                                        var ladelEndPoint = line.Start + scale * vec;
                                        scale = radius / vec.Length();
                                        var textPoint = ladelEndPoint + scale * vec;
                                        lcAxisLine.StartLeadLines = new List<LcLine>() { CreateLcLine(line.Start, ladelEndPoint) };
                                        lcAxisLine.StartCircleHandle = new List<LcAxisCircle>() { CreateLcAxisCirle(textPoint, radius, axisNumText) };
                                    }
                                    else
                                    {
                                        var vec = line.End - line.Start;
                                        var scale = 1000 / vec.Length();
                                        var ladelEndPoint = line.End + scale * vec;
                                        scale = radius / vec.Length();
                                        var textPoint = ladelEndPoint + scale * vec;
                                        lcAxisLine.EndLeadLines = new List<LcLine>() { CreateLcLine(line.End, ladelEndPoint) };
                                        lcAxisLine.EndCircleHandle = new List<LcAxisCircle>() { CreateLcAxisCirle(textPoint, radius, axisNumText) };
                                    }
                                }
                                else if ((win.AxisNumType == "对侧标注"))
                                {
                                    if (GeoUtils.PointDistanceToLine(line.Start, selectPoint1, selectPoint2) < GeoUtils.PointDistanceToLine(line.End, selectPoint1, selectPoint2))
                                    {
                                        var vec = line.End - line.Start;
                                        var scale = 1000 / vec.Length();
                                        var ladelEndPoint = line.End + scale * vec;
                                        scale = radius / vec.Length();
                                        var textPoint = ladelEndPoint + scale * vec;
                                        lcAxisLine.EndLeadLines = new List<LcLine>() { CreateLcLine(line.End, ladelEndPoint) };
                                        lcAxisLine.EndCircleHandle = new List<LcAxisCircle>() { CreateLcAxisCirle(textPoint, radius, axisNumText) };
                                    }
                                    else
                                    {


                                        var vec = line.Start - line.End;
                                        var scale = 1000 / vec.Length();
                                        var ladelEndPoint = line.Start + scale * vec;
                                        scale = radius / vec.Length();
                                        var textPoint = ladelEndPoint + scale * vec;
                                        lcAxisLine.StartLeadLines = new List<LcLine>() { CreateLcLine(line.Start, ladelEndPoint) };
                                        lcAxisLine.StartCircleHandle = new List<LcAxisCircle>() { CreateLcAxisCirle(textPoint, radius, axisNumText) };
                                    }
                                }
                                axisNumInt++;
                            }
                            goto Step1_1;
                        }
                        goto End;
                    }
                }
                else { goto End; }
            }
        End:
            this.inputer = null;
            this.EndCreating();
            //DocumentManager.CurrentRecorder.CancleAction();

        }

        private LcLine CreateLcLine(Vector2 startPoint, Vector2 endPoint)
        {
            LcLine lcLine = docRt.Document.CreateObject<LcLine>();
            lcLine.Start = startPoint;
            lcLine.End = endPoint;
            return lcLine;
        }
        private LcAxisCircle CreateLcAxisCirle(Vector2 point, double radius, string text)
        {
            LcAxisCircle lcAxisCircle = docRt.Document.CreateObject<LcAxisCircle>();
            LcCircle lcCircle = docRt.Document.CreateObject<LcCircle>();
            lcCircle.Center = point;
            lcCircle.Radius = radius;
            lcAxisCircle.LcCircle = lcCircle;
            LcText lcText = docRt.Document.CreateObject<LcText>();
            lcText.Text = text;
            lcText.TextStart = point;
            lcText.Boxstart = point;
            lcText.Start = point;
            lcText.Heigh = radius;
            //字体
            lcText.Typeface = "宋体";
            //向量
            //lcText.XLpoint = new Vector2(text.Normal.X, text.Normal.Y); 
            //默认值
            lcText.Tilt = 0;
            lcText.Widthfactor = 1;
            //计算文字角度
            lcText.Rotate = 0;
            lcText.Alignment = "居中";
            lcAxisCircle.LcText = lcText;
            return lcAxisCircle;
        }
        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offSet)
        {
            Draw(canvas, element, Matrix3.GetTranslate(offSet));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var lcAxisGrid = element as LcAxisGrid;
            //var mat = matrix * Matrix3.GetTranslate(lcAxisGrid.BasePoint.Clone().Add(new Vector2(-LcAxisGrid.offValue, -LcAxisGrid.offValue)));
            foreach (LcAxisLine lcAxisLine in lcAxisGrid.Elements)
            {
                var LeadLineAction = lcAxisLine.RtAction as ElementAction;
                LeadLineAction.SetViewport(this.vportRt).Draw(canvas, lcAxisLine, matrix);
            }



            if (matrix == Matrix3.Identity)
            {
                //var leftTop = this.vportRt.ConvertWcsToScr(lcDrawing.BoundingBox.LeftTop);
                //var rightBottom = this.vportRt.ConvertWcsToScr(lcDrawing.BoundingBox.RightBottom);
                //canvas.DrawRect((float)leftTop.X, (float)leftTop.Y, (float)rightBottom.X - (float)leftTop.X, (float)rightBottom.Y - (float)leftTop.Y, Constants.SilverPen);
            }
        }
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var lcAxisGrid = element as LcAxisGrid; //getHel
            var grips = new List<ControlGrip>();

            var insertPoint = new ControlGrip
            {
                Element = lcAxisGrid,
                Name = "InsertPoint",
                Position = lcAxisGrid.BasePoint
            };
            grips.Add(insertPoint);
            return grips.ToArray();
        }

        public override SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2 point, bool forRef, Vector2 PrePoint = null)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var lcAxisGrid = element as LcAxisGrid;
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { Element = element };
            if (sscur.ObjectOn)
            {

          
                foreach (LcAxisLine axisLine in lcAxisGrid.Elements)
                {

                    var line2d = axisLine.AxisLine.Line;
                    if (sscur.PointType.Has(SnapPointType.Endpoint))
                    {
                        if ((point - line2d.Start).Length() <= maxDistance)
                        {
                            result.Point = line2d.Start;
                            result.Name = "Start";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, line2d));
                        }
                        else if ((point - line2d.End).Length() <= maxDistance)
                        {
                            result.Point = line2d.End;
                            result.Name = "End";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, line2d));
                        }
                    }
                }
                if (sscur.PointType.Has(SnapPointType.Midpoint) && result.Point == null)
                {
                    foreach (LcAxisLine axisLine in lcAxisGrid.Elements)
                    {
                        var line = axisLine.AxisLine.Line;

                        var cp = (line.Start + line.End) / 2;
                        if ((point - cp).Length() <= maxDistance)
                        {
                            result.Point = cp;
                            result.Name = "Mid";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Midpoint, line));
                        }
                    }
                }
                //forRef时只捕捉端点，中点等，如果
                if (!forRef && result.Point == null)
                {
                    foreach (LcAxisLine axisLine in lcAxisGrid.Elements)
                    {
                        var line = axisLine.AxisLine.Line;

                        var refPoints = snapRt.GetRefPoints(element);
                        var lineLength = (line.End - line.Start).Length();
                        var distance = GeoUtils.PointToLineDistance(line.Start, line.End, point, out Vector2 nearest, out double dirDistance);
                        if (sscur.PointType.Has(SnapPointType.Nearest))
                        {
                            //最近点必须在线段内进行测试
                            if (distance < maxDistance && dirDistance > 0 && dirDistance < lineLength)
                            {
                                result.Point = nearest;
                                result.Name = "Nearest";
                                result.Curves.Add(new SnapRefCurve(SnapPointType.Nearest, line));
                            }
                        }
                        //进行延长线上点捕捉，需要元素上有参考点
                        if (sscur.PointType.Has(SnapPointType.ExtensionLine) && refPoints.Count > 0 && result.Point == null)
                        {
                            if (distance < maxDistance)
                            {
                                result.Point = nearest;
                                result.Name = "Extension";
                                result.Curves.Add(new SnapRefCurve(SnapPointType.ExtensionLine, line));
                            }
                        }
                    }
                }
                List<Vector2> crossVectorPoints = lcAxisGrid.CrossVectorPoints;
                
                if (sscur.PointType.Has(SnapPointType.Intersection))
                {
                    foreach (Vector2 vector2 in crossVectorPoints)
                    {

                        if ((point - vector2).Length() <= maxDistance)
                        {
                            result.Point = vector2;
                            result.Name = "Intersection";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Endpoint, new Line2d(vector2, vector2)));
                            break;
                        }
                    }
                }
            }

            if (result.Point != null)
                return result;
            else
                return null;
        }
        public override SnapPointResult SnapLine(SnapRuntime snapRt, List<Vector2> vector2s, Vector2 point, bool forRef)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { };
            if (sscur.ObjectOn)
            {

                if (sscur.PointType.Has(SnapPointType.Intersection))
                {
                    foreach (Vector2 vector2 in vector2s)
                    {
                        if ((point - vector2).Length() <= maxDistance)
                        {
                            result.Point = vector2;
                            result.Name = "Intersection";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Intersection, new Line2d(vector2, vector2)));
                        }
                    }
                }
            }
            if (result.Point != null)
                return result;
            else
                return null;
        }
        //public override List<PropertyObserver> GetPropertyObservers()
        //{


        //    return new List<PropertyObserver>()
        //               {
        //                   new PropertyObserver()
        //                       {
        //                            Name = "组名",
        //                            DisplayName = "组名",
        //                            CategoryName = "Geometry",
        //                            CategoryDisplayName = "文字",
        //                            Getter = (ele) => (ele as LcAxisGrid).Name,
        //                            Setter = (ele, value) =>
        //                               {
        //                                   var lctext = (ele as LcAxisGrid);
        //                                   string textvalue = value.ToString();
        //                                   if(textvalue!=""){
        //                                   lctext.Set(name: textvalue);
        //                                   }

        //                               }
        //                       }

        //               };
        //}

        LcAxisGrid _lcAxisGrid;
        private string _gripName;
        Vector2 _position;
        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var lcAxisGrid = element as LcAxisGrid;
            _lcAxisGrid = lcAxisGrid;


            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                Vector2 dragpoint = position;

                if (this.vportRt.SnapRt?.Current != null)
                {
                    dragpoint = this.vportRt.SnapRt.Current.SnapPoint;
                }
                if (gripName == "InsertPoint")
                {
                    lcAxisGrid.Set(basePoint: dragpoint);
                    lcAxisGrid.ResetBoundingBox();
                    foreach (var ele in lcAxisGrid.Elements)
                    {
                        ele.ResetBoundingBox();
                    }
                }

            }

        }

        public override void DrawDragGrip(SKCanvas canvas)
        {
            //if (_lcAxisGrid == null) return;

            //foreach (LcAxisLine lcAxisLine in _lcAxisGrid.Elements)
            //{

            //    var start = this.vportRt.ConvertWcsToScr(lcAxisLine.AxisLine.Start);
            //    if (_gripName == "Start")
            //        start = this.vportRt.ConvertWcsToScr(_position);

            //    var end = this.vportRt.ConvertWcsToScr(lcAxisLine.AxisLine.End);
            //    if (_gripName == "End")
            //        end = this.vportRt.ConvertWcsToScr(_position);

            //    canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), Constants.draggingPen);
            //}

        }

        public override void DrawAuxLines(SKCanvas canvas)
        {

            //var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            //var movePoint = mp.ToSKPoint();
            //if (_lcAxisGrid == null) return;

            //foreach (LcAxisLine lcAxisLine in _lcAxisGrid.Elements)
            //{

            //    var Wcs = this.vportRt.ConvertScrToWcs(mp);
            //    Vector2 start = Wcs + lcAxisLine.AxisLine.Start;
            //    Vector2 end = Wcs - lcAxisLine.AxisLine.End;
            //    DrawLine(start, end);
            //}

            //void DrawLine(Vector2 vStart, Vector2 vEnd)
            //{
            //    var start = this.vportRt.ConvertWcsToScr(vStart).ToSKPoint();
            //    var end = this.vportRt.ConvertWcsToScr(vEnd).ToSKPoint();
            //    using (var pen = new SKPaint { Color = SKColors.Green, IsStroke = true })
            //    {
            //        canvas.DrawLine(start, end, pen);
            //    }
            //}

        }
    }
}
